package code.java;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 虚引用:
 *  1. 当对象被回收的时候, 会放到Queue中, 使用其它的线程可以监听到被回收的对象.
 *  2. 使用场景：
 *      1. 使用NIO这种堆外内存的时候, 当对象被回收的时候, 就能够使用Queue获取到这个对象.
 *      2. 相应的回收掉堆外内存。
 */
public class PhantomReferenceTest {

    private static final List<Object> LIST = new ArrayList<>();
    private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();

    public static void main(String[] args) {
        PhantomReference<M> reference = new PhantomReference<>(new M("Alex"), QUEUE);

        Thread t1 = new Thread(() -> {
            while (true) {
                LIST.add(new byte[1024 * 1024]);
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println(reference.get());
            }
        });

        t1.start();

        Thread t2 = new Thread(() -> {
            while (true) {
                Reference<? extends M> poll = QUEUE.poll();
                if (poll != null) {
                    System.out.println("GC" + poll);
                }
            }
        });
        t2.start();
    }
}


class M {

    public String name;

    public M(String name) {
        this.name = name;
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize!");
    }

    @Override
    public String toString() {
        return name;
    }
}
